package com.blog.cloud.gateway.filter;

import cn.hutool.system.UserInfo;
import com.blog.cloud.gateway.constants.TokenConstant;
import com.blog.cloud.gateway.utils.JwtTokenUtil;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;

import java.util.Objects;

@RequiredArgsConstructor
public class JwtAuthenticationFilter implements WebFilter {
    private final RedisTokenStore redisTokenStore;

    @Override
    @SneakyThrows
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) {
        String token = JwtTokenUtil.getToken(request);

        // 如果请求中没有认证信息则表示未登录状态
        if (StringUtils.isBlank(token)) {
            chain.doFilter(request, response);
            return;
        }

        // 如果有则开始认证过程
        UserInfo userInfo = redisTokenStore.getUserInfo(token);
        if (Objects.isNull(userInfo)) {
            chain.doFilter(request, response);
            return;
        }

        // 如果redis中有则表明登陆状态还有效，直接使用
        Authentication authentication = new UsernamePasswordAuthenticationToken(userInfo.getUsername(), userInfo.getPassword(), userInfo.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authentication);
        chain.doFilter(request, response);
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        String token = JwtTokenUtil.getToken(exchange);
        // 如果token为空，则继续过滤
        if (!StringUtils.hasText(token)) {
            chain.filter(exchange);
            return Mono.empty();
        }
        // 如果token不为空，则验证token
        String realToken = token.replaceFirst(TokenConstant.TOKEN_PREFIX, "");
        // 如果realToken还未过期
        if (JwtTokenUtil.verifyToken(realToken)) {
            Long userId = JwtTokenUtil.parseToken(realToken);

        }

        return null;
    }
}

// 如果请求头带有token认证信息，则表明可能登陆过，因此在请求时先判断token有没有过期，如果redis中查不到信息，则过期，反之有效，然后从中取出用户认证信息,直接放入认证容器
// 因此在登录存放认证信息时也要存放认证对象才行
// spring security 默认的表单登录使用的是 UsernamePasswordAuthenticationFilter 过滤器，这里面进行了认证过程，自定义的并没有这个过滤器